package com.hnas.core.dao;

import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;

/**
 * 
 * @author 郑兴(zhengxing)
 *
 * @param <B>
 */
@Repository
public abstract class CardAppBaseDaoImpl<B> implements BaseDao<B> {
	protected EntityManager entityManager;
	private Class<B> queryClass;

	public CardAppBaseDaoImpl(Class<B> queryClass) {
		super();
		this.queryClass = queryClass;
	}
	public CardAppBaseDaoImpl(Class<B> queryClass, EntityManager em) {
		super();
		this.queryClass = queryClass;
		this.entityManager = em;
	}
	
	public B getNewInstance() {
		try {
			return getQueryClass().newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException("Error creating new instance of : " + getQueryClass().getName(), e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException("Error creating new instance of : " + getQueryClass().getName(), e);
		}
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#findById(java.lang.Object)
	 */
	public B find(Object id) {
		return (B)entityManager.find(queryClass, id);
	}
	
	/* (non-Javadoc)
	 * @see com.hna.dt.dao.BaseDao#get(java.lang.Object)
	 */
	public B get(Object id) {
		return (B)entityManager.getReference(queryClass, id);
	}
	

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#findByNamedQuery(java.lang.String, java.lang.Object[])
	 */
	@SuppressWarnings("unchecked")
	public List<B> findByNamedQuery(String queryName, Object... objects) {
		Query queryObject = entityManager.createNamedQuery(queryName);
		int i = 1;
		for(Object obj : objects) {
			queryObject.setParameter(i++, obj);
		}
		return queryObject.getResultList();
	}
	
	public List<B> findByQuery(String query, Object... objects) {
		Query queryObject = entityManager.createQuery(query);
		int i = 1;
		for(Object obj : objects) {
			queryObject.setParameter(i++, obj);
		}
		return queryObject.getResultList();
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#findByNamedQueryAndNamedParams(java.lang.String, java.util.Map)
	 */
	@SuppressWarnings("unchecked")
	public List<B> findByNamedQueryAndNamedParams(String queryName, Map<String, Object> paramMap) {
		Query queryObject = entityManager.createNamedQuery(queryName);
		if (paramMap != null) {
			for (Map.Entry<String, ?> entry : paramMap.entrySet()) {
				queryObject.setParameter(entry.getKey(), entry.getValue());
			}
		}
		return queryObject.getResultList();
	}
	public List<B> findByQueryAndNamedParams(String queryName, Map<String, Object> paramMap) {
		Query queryObject = entityManager.createQuery(queryName);
		if (paramMap != null) {
			for (Map.Entry<String, ?> entry : paramMap.entrySet()) {
				queryObject.setParameter(entry.getKey(), entry.getValue());
			}
		}
		return queryObject.getResultList();
	}
	
	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#getReference(java.lang.Object)
	 */
	public B getReference(Object id) {
		return (B) entityManager.getReference(queryClass, id);
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#persist(B)
	 */
	public void persist(B obj) {
		entityManager.persist(obj);
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#merge(B)
	 */
	public void merge(B obj) {
		entityManager.merge(obj);
	}
	
	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#refresh(B)
	 */
	public void refresh(B obj) {
		entityManager.refresh(obj);
	}

	/* (non-Javadoc)
	 * @see com.hna.mars.dao.BaseDao#remove(B)
	 */
	public void remove(B obj) {
		entityManager.remove(obj);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.hna.dt.dao.BaseDao#lock(java.lang.Object, javax.persistence.LockModeType)
	 */
	public void lock(final B obj, final LockModeType type) {
		entityManager.lock(obj, type);		
	}

	public Class<B> getQueryClass() {
		return queryClass;
	}

	public void setQueryClass(Class<B> queryClass) {
		this.queryClass = queryClass;
	}

	/**
	 * @return the entityManager
	 */
	public EntityManager getEntityManager() {
		return entityManager;
	}

	/**
	 * @param entityManager the entityManager to set
	 */
	@PersistenceContext(unitName="CardApp")
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

//	@Override
	public Long count(String query, Object... objects) {
		// TODO Auto-generated method stub
		Query queryObject = entityManager.createQuery(query);
		int i = 1;
		for(Object obj : objects) {
			queryObject.setParameter(i++, obj);
		}
		return (Long) queryObject.getSingleResult();
	}

//	@Override
	public List<B> findByRange(String query, int startIndex, int rowCount,
			Object... objects) {
		// TODO Auto-generated method stub
		Query queryObject = entityManager.createQuery(query);
		int i = 1;
		for(Object obj : objects) {
			queryObject.setParameter(i++, obj);
		}
		if (startIndex>=0){
			queryObject.setFirstResult(startIndex);
		}
		if (rowCount > 0) {
			queryObject.setMaxResults(rowCount);
		}
		return queryObject.getResultList();
//		return null;
	}

//	@Override
	public void queryByPage(PageBean<B> page, Object... objects) {
		// TODO Auto-generated method stub
		int firstRow = (page.getPageNo() - 1) * page.getPageSize();
		if (firstRow < 0) {
			firstRow = 0;
			page.setPageNo(1);
		}
		int maxRows = page.getPageSize();
		if (maxRows <= 0) {
			maxRows = 20;
			page.setPageSize(20);
		}
		List<B> list= this.findByRange(page.getQuery(),firstRow,maxRows, objects);
		page.setList(list);
		if (page.getTotalCount()<0){
			Long count = this.count(page.getQueryCount(), objects);
			if (null!=count)
				page.setTotalCount(count.intValue());
		}
	}
}
